/******************************************************************************* 
 * Copyright (c) 2008 xored software, Inc.  
 * 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution, and is available at 
 * http://www.eclipse.org/legal/epl-v10.html  
 * 
 * Contributors: 
 *     xored software, Inc. - initial API and Implementation (Yuri Strot) 
 *******************************************************************************/
package com.xored.glance.internal.items;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Composite;

import com.xored.glance.core.IMatch;
import com.xored.glance.core.ITextBlock;
import com.xored.glance.core.ITextContainer;
import com.xored.glance.core.StyleList;

/**
 * @author Yuri Strot
 * 
 */
public abstract class ItemControl implements ITextContainer {

	protected ItemDecorator decorator;
	protected Composite composite;

	public ItemControl(Composite composite) {
		decorator = new ItemDecorator(composite, getItemProvider());
		this.composite = composite;
	}

	protected abstract ItemProvider getItemProvider();

	private List<ItemCell> cells;

	protected abstract void collectCells(List<ItemCell> cells);

	protected List<ItemCell> getCells() {
		if (cells == null) {
			cells = new ArrayList<ItemCell>();
			collectCells(cells);
		}
		return cells;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextControl#getText()
	 */
	public ITextBlock[] getText() {
		return getCells().toArray(new ITextBlock[getCells().size()]);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextContainer#getFont()
	 */
	public Font getFont() {
		return composite.getFont();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xored.glance.core.ITextControl#select(com.xored.glance.core.IMatch)
	 */
	public void select(IMatch match) {
		ItemMatch tMatch = (ItemMatch) match;
		if (tMatch != null) {
			getItemProvider().show(tMatch.getCell().getItem());
		}

		setMatch(tMatch);
	}

	public void dispose() {
		if (selection != null) {
			getItemProvider().select(selection.getCell().getItem());
		}
		decorator.dispose();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xored.glance.core.ITextControl#show(com.xored.glance.core.IMatch[])
	 */
	public void show(IMatch[] matches) {
		setMatches(matches);
	}

	public void setMatch(ItemMatch match) {
		if (selection != null) {
			ItemCell cell = selection.getCell();
			selection = null;
			updateCell(cell);
		}
		selection = match;
		if (selection != null)
			updateCell(selection.getCell());
		decorator.redraw();
	}

	protected Color getFgSelection() {
		return composite.getDisplay().getSystemColor(
				SWT.COLOR_LIST_SELECTION_TEXT);
	}

	protected Color getBgSelection() {
		return composite.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
	}

	protected Color getFgHighlight() {
		return composite.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
	}

	protected Color getBgHighlight() {
		return composite.getDisplay().getSystemColor(SWT.COLOR_YELLOW);
	}

	public void setMatches(IMatch[] matches) {
		cellToMatches = new HashMap<ItemCell, List<ItemMatch>>();
		for (IMatch match : matches) {
			ItemMatch tMatch = (ItemMatch) match;
			ItemCell cell = tMatch.getCell();
			List<ItemMatch> list = cellToMatches.get(cell);
			if (list == null) {
				list = new ArrayList<ItemMatch>();
				cellToMatches.put(cell, list);
			}
			list.add(tMatch);
		}
		decorator.clearStyles();
		for (ItemCell cell : cellToMatches.keySet()) {
			updateCell(cell);
		}
		decorator.redraw();
	}

	protected void updateCell(ItemCell cell) {
		List<StyleRange> ranges = new ArrayList<StyleRange>();
		if (cellToMatches != null) {
			List<ItemMatch> itemMatches = cellToMatches.get(cell);
			if (itemMatches != null) {
				for (ItemMatch match : itemMatches) {
					StyleRange range = new StyleRange(match.getOffset(), match
							.getLength(), getFgHighlight(), getBgHighlight());
					ranges.add(range);
				}
			}
		}
		StyleList styles = new StyleList(ranges.toArray(new StyleRange[ranges
				.size()]));
		if (selection != null && cell.equals(selection.getCell())) {
			StyleRange range = new StyleRange(selection.getOffset(), selection
					.getLength(), getFgSelection(), getBgSelection());
			styles = styles.applyStyles(new StyleList(range));
		}
		decorator.setStyles(cell, styles);
	}

	private ItemMatch selection;
	private Map<ItemCell, List<ItemMatch>> cellToMatches;
}
